﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VIES
{
    /// <summary>
    /// Provides an abstract API to access available functions
    /// of the VIES-on-the-Web service.
    /// </summary>
    /// <see cref="http://ec.europa.eu/taxation_customs/vies/"/>
    ///<remarks>Philipp Schosteritsch, SCHOSTE.COM</remarks>
    public class WebService
    {
        #region Contracts (Invariants)
        [System.Diagnostics.Contracts.ContractInvariantMethod]
        private void InvariantInstance()
        {
            System.Diagnostics.Contracts.Contract.Invariant(WebService._instance != null);
            System.Diagnostics.Contracts.Contract.Invariant(WebService._instance._checkVatService != null);
        }
        #endregion

        private static WebService _instance = null;
        private readonly checkVatService _checkVatService;

        private WebService()
        {
            this._checkVatService = new checkVatService();
        }

        /// <summary>
        /// Returns the reference to the web service library
        /// </summary>
        public static WebService Instance
        {
            get
            {
                #region Contracts
                System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<WebService>() != null);
                #endregion

                if (WebService._instance == null) WebService._instance = new WebService();

                return WebService._instance;
            }
        }

        /// <summary>
        /// Checks if a VAT number is valid
        /// </summary>
        /// <param name="vatNumber">The VAT number to check</param>
        /// <returns>Information about the sumbitted VAT number. The Valid field
        /// indicates whether the number is valid or nor</returns>
        /// <exception cref="ArgumentNullException">Thrown if the VATNumber is null</exception>
        /// <exception cref="ArgumentException">Thrown if the VATNumber is invalid</exception>
        public VATInformation Verify(string vatNumber)
        {
            #region Contracts
            System.Diagnostics.Contracts.Contract.Requires(vatNumber != null);
            System.Diagnostics.Contracts.Contract.Requires(vatNumber.Length >= 2);
            System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<VATInformation>() != null);
            System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<VATInformation>().VATNumber != null);
            System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<VATInformation>().Name != null);
            System.Diagnostics.Contracts.Contract.Ensures(System.Diagnostics.Contracts.Contract.Result<VATInformation>().Address != null);
            #endregion

            if (vatNumber == null) throw new ArgumentNullException("vatNumber");
            if (vatNumber.Length < 2) throw new ArgumentException(Resources.ParamInvalidVat, "vatNumber");

            try
            {
                var countryCode = vatNumber.Substring(0, 2);
                var number = vatNumber.Substring(2);
                var name = "";
                var address = "";
                var isValid = false;
                var dt = this._checkVatService.checkVat(ref countryCode, ref number, out isValid, out name, out address);

                return new VATInformation(vatNumber, name, address, isValid);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(Resources.CheckVatException, ex);
            }
        }
    }
}
